﻿// Copyright (c) ServiceStack, Inc. All Rights Reserved.
// License: https://raw.github.com/ServiceStack/ServiceStack/master/license.txt


using System;
using System.Collections.Generic;
using System.Reflection;
using Funq;
using NUnit.Framework;
using ServiceStack.Configuration;
using ServiceStack.Host;
using ServiceStack.Messaging;
using ServiceStack.RabbitMq;
using ServiceStack.Redis;
using ServiceStack.Text;
using Custom;
using ServiceStack;

namespace ServiceStack.WebHost.Endpoints.Tests
{
    [TestFixture]
    public class FreeLicenseUsageServiceClientTests : LicenseUsageTests
    {
        [SetUp]
        public void SetUp()
        {
            LicenseUtils.RemoveLicense();
            JsConfig.Reset();
        }

        [TearDown]
        public void TearDown()
        {
    //            Licensing.RegisterLicense(new AppSettings().GetString("servicestack:license"));
            Licensing.RegisterLicense(Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE"));
        }

        [Test]
        public void Allows_registration_of_10_operations()
        {
            using var appHost = new LicenseTestsAppHost(typeof(Services10));
            appHost.Init();
            appHost.Start(Config.ListeningOn);

            appHost.Metadata.GetOperationDtos().Map(x => x.Name).PrintDump();
            Assert.That(appHost.Metadata.GetOperationDtos().Count, Is.EqualTo(10));
        }

        [Test]
        public void Throws_on_registration_of_11_operations()
        {
            using var appHost = new NoLicenseTestsAppHost(typeof(Services10), typeof(Service1));
            Assert.Throws(Is.TypeOf<LicenseException>()
                    .Or.TypeOf<TargetInvocationException>()
                    .With.Property("InnerException").TypeOf<LicenseException>(),
                () => {
                    appHost.Init();
                    appHost.Start(Config.ListeningOn);
                });
        }

        [Ignore("TODO: Ignore reason"), Test]
        public void Allows_MegaDto_through_ServiceClient()
        {
            using var appHost = new LicenseTestsAppHost(typeof(MegaDtoService));
            appHost.Init();
            appHost.Start(Config.ListeningOn);

            var client = new JsonServiceClient(Config.AbsoluteBaseUri);

            var request = MegaDto.Create();

            var response = client.Post(request);
            Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id));

            Assert.Throws<LicenseException>(() =>
                request.ToJson());

            response = client.Post(request);
            Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id));

            Assert.Throws<LicenseException>(() =>
                MegaDto.Create().ToJson());
        }
    }

    [TestFixture]
    public class FreeUsageRabbitMqClientTests : LicenseUsageTests
    {
        [Ignore("Integration Test"), Test]
        public void Allows_MegaDto_through_RabbitMqClients()
        {
            var mqFactory = new RabbitMqMessageFactory(connectionString: Config.RabbitMQConnString);

            var request = MegaDto.Create();

            using (var mqClient = mqFactory.CreateMessageProducer())
            {
                mqClient.Publish(request);
            }

            using (var mqClient = mqFactory.CreateMessageQueueClient())
            {
                var msg = mqClient.Get<MegaDto>(QueueNames<MegaDto>.In);
                var response = msg.GetBody();

                Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id));
            }
        }
    }

    [TestFixture]
    public class FreeUsageRedisMqClientTests : LicenseUsageTests
    {
        [Test]
        public void Allows_MegaDto_through_RedisMqClients()
        {
            var mqFactory = new RedisMessageFactory(new BasicRedisClientManager());

            var request = MegaDto.Create();

            using (var mqClient = mqFactory.CreateMessageProducer())
            {
                mqClient.Publish(request);
            }

            using (var mqClient = mqFactory.CreateMessageQueueClient())
            {
                var msg = mqClient.Get<MegaDto>(QueueNames<MegaDto>.In);
                var response = msg.GetBody();

                Assert.That(request.T01.Id, Is.EqualTo(response.T01.Id));
            }
        }
    }

    [TestFixture]
    public class RegisteredLicenseUsageTests : LicenseUsageTests
    {
        [Test]
        public void Allows_registration_of_11_operations()
        {
    //            Licensing.RegisterLicense(new AppSettings().GetString("servicestack:license"));
            Licensing.RegisterLicense(Environment.GetEnvironmentVariable("SERVICESTACK_LICENSE"));

            using var appHost = new LicenseTestsAppHost(typeof(Services10), typeof(Service1));
            appHost.Init();
            appHost.Start(Config.ListeningOn);

            Assert.That(appHost.Metadata.GetOperationDtos().Count, Is.EqualTo(11));
        }
    }

    public class LicenseUsageTests
    {
        protected class LicenseTestsAppHost : AppHostHttpListenerBase
        {
            private readonly List<Type> services;
            public LicenseTestsAppHost(params Type[] services)
                : base(nameof(LicenseTestsAppHost))
            {
                this.services = new List<Type>(services);
            }

            protected override ServiceController CreateServiceController(params Assembly[] assembliesWithServices)
            {
                return new ServiceController(this, () => services);
            }

            public override void Configure(Container container)
            {
                Plugins.RemoveAll(x => x is NativeTypesFeature);
                Plugins.RemoveAll(x => x is UiFeature);
                GetPlugin<MetadataFeature>().ServiceRoutes.Clear();
            }
        }

        protected class NoLicenseTestsAppHost : LicenseTestsAppHost
        {
            public NoLicenseTestsAppHost(params Type[] services)
                : base(services) {}

            public override void OnConfigLoad()
            {
                base.OnConfigLoad();
                LicenseUtils.RemoveLicense();
            }
        }
    }
}

namespace Custom
{
    public class T01 { public int Id { get; set; } }
    public class T02 { public int Id { get; set; } }
    public class T03 { public int Id { get; set; } }
    public class T04 { public int Id { get; set; } }
    public class T05 { public int Id { get; set; } }
    public class T06 { public int Id { get; set; } }
    public class T07 { public int Id { get; set; } }
    public class T08 { public int Id { get; set; } }
    public class T09 { public int Id { get; set; } }
    public class T10 { public int Id { get; set; } }
    public class T11 { public int Id { get; set; } }
    public class T12 { public int Id { get; set; } }
    public class T13 { public int Id { get; set; } }
    public class T14 { public int Id { get; set; } }
    public class T15 { public int Id { get; set; } }
    public class T16 { public int Id { get; set; } }
    public class T17 { public int Id { get; set; } }
    public class T18 { public int Id { get; set; } }
    public class T19 { public int Id { get; set; } }
    public class T20 { public int Id { get; set; } }
    public class T21 { public int Id { get; set; } }

    public class Services10 : IService
    {
        public void Any(T01 request) { }
        public void Any(T02 request) { }
        public void Any(T03 request) { }
        public void Any(T04 request) { }
        public void Any(T05 request) { }
        public void Any(T06 request) { }
        public void Any(T07 request) { }
        public void Any(T08 request) { }
        public void Any(T09 request) { }
        public void Any(T10 request) { }
    }

    public class Service1 : IService
    {
        public void Any(T11 request) { }
    }

    public class MegaDto : IReturn<MegaDto>
    {
        public T01 T01 { get; set; }
        public T02 T02 { get; set; }
        public T03 T03 { get; set; }
        public T04 T04 { get; set; }
        public T05 T05 { get; set; }
        public T06 T06 { get; set; }
        public T07 T07 { get; set; }
        public T08 T08 { get; set; }
        public T09 T09 { get; set; }
        public T10 T10 { get; set; }
        public T11 T11 { get; set; }
        public T12 T12 { get; set; }
        public T13 T13 { get; set; }
        public T14 T14 { get; set; }
        public T15 T15 { get; set; }
        public T16 T16 { get; set; }
        public T17 T17 { get; set; }
        public T18 T18 { get; set; }
        public T19 T19 { get; set; }
        public T20 T20 { get; set; }
        public T21 T21 { get; set; }

        public static MegaDto Create()
        {
            return new MegaDto
            {
                T01 = new T01 { Id = 1 },
                T02 = new T02 { Id = 1 },
                T03 = new T03 { Id = 1 },
                T04 = new T04 { Id = 1 },
                T05 = new T05 { Id = 1 },
                T06 = new T06 { Id = 1 },
                T07 = new T07 { Id = 1 },
                T08 = new T08 { Id = 1 },
                T09 = new T09 { Id = 1 },
                T10 = new T10 { Id = 1 },
                T11 = new T11 { Id = 1 },
                T12 = new T12 { Id = 1 },
                T13 = new T13 { Id = 1 },
                T14 = new T14 { Id = 1 },
                T15 = new T15 { Id = 1 },
                T16 = new T16 { Id = 1 },
                T17 = new T17 { Id = 1 },
                T18 = new T18 { Id = 1 },
                T19 = new T19 { Id = 1 },
                T20 = new T20 { Id = 1 },
                T21 = new T21 { Id = 1 },
            };
        }
    }

    public class MegaDtoService : IService
    {
        public object Any(MegaDto request)
        {
            return request;
        }
    }
}

